/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package evidence.model;

import evidence.model.pomocneTridy.SaveTimerTask;
import evidence.controler.Controler;
import evidence.model.modeloveTridy.DenniZaznam;
import evidence.model.modeloveTridy.Klient;
import evidence.model.modeloveTridy.Klienti;
import evidence.model.modeloveTridy.MesicniEvidence;
import evidence.model.modeloveTridy.TypSluzby;
import evidence.model.modeloveTridy.Ukony;
import evidence.model.pomocneTridy.Time;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.xml.sax.SAXException;

/**
 *
 * @author Protheo
 */
public class Model extends AbstractModel implements IModel, Serializable {

    public static final long serialVersionUID = 1;
    public static final int SETTINGS_KLIENTI = 0;
    public static final int SETTINGS_UKONY = 1;
    public static final int SETTINGS_VZOR = 2;
    public static final int SETTINGS_EVI = 3;
    public static final int SETTINGS_USER = 4;
    public static final int SETTINGS_XLS = 5;
    private final String USERDATA = "userdata" + File.separator + "settings.xml";
    private final String SETTINGS_ERROR_MSG = "";
    private final String SETTINGS_ERROR_TITLE = "";
    private final long TIMEDEALY = 300000;
    private MesicniEvidence mesic;
    private File mesicFile;
    private File xslVzor;
    private Klienti klienti;
    private Ukony ukony;
    private Map<Integer, String> nastaveni;
    private Boolean monthSaved = true;
    private Timer casovac;

    public Model() {
        nastaveni = new HashMap<Integer, String>();
        try {
            File settings = new File(USERDATA);
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(settings);
            NodeList paths = doc.getElementsByTagName("path");
            nastaveni.put(SETTINGS_KLIENTI, paths.item(0).getTextContent());
            nastaveni.put(SETTINGS_UKONY, paths.item(1).getTextContent());
            nastaveni.put(SETTINGS_VZOR, paths.item(2).getTextContent());
            nastaveni.put(SETTINGS_XLS, paths.item(3).getTextContent());
            nastaveni.put(SETTINGS_EVI, paths.item(4).getTextContent());
            nastaveni.put(SETTINGS_USER, doc.getElementsByTagName("name").item(0).getTextContent());
            this.loadData();
        } catch (SAXException ex) {
            Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            this.firePropertyChange(Controler.ERROR_SETTINGS, this.SETTINGS_ERROR_MSG, this.SETTINGS_ERROR_TITLE);
            Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void loadData() {
        klienti = new Klienti(this.getSetting(SETTINGS_KLIENTI));
        ukony = new Ukony(this.getSetting(SETTINGS_UKONY));
        Klient.setUkony(ukony);
        casovac = new Timer();
        casovac.schedule(new SaveTimerTask(this), TIMEDEALY, TIMEDEALY);
        xslVzor = new File(this.getSetting(SETTINGS_VZOR));
    }

    public Integer newMonth(int rok, int mesic) {
        this.mesic = new MesicniEvidence(rok, mesic);
        return this.mesic.getPocetDnu();
    }

    public Integer openMonth(File cesta) {
        if (cesta != null && cesta.exists()) {
            try {
                ObjectInputStream is = new ObjectInputStream(new FileInputStream(cesta));
                this.mesic = (MesicniEvidence) is.readObject();
                this.mesicFile = cesta;
                return this.mesic.getPocetDnu();
            } catch (FileNotFoundException ex) {
                Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return -1;
    }

    public List<List<Object>> getDay(int den) {
        return this.mesic.getDay(den);
    }

    public void addDenniZaznam(int den, Time zacatek, Time konec, String typ, String klient, String ukon, int doprava, Boolean prestavka, String nepritomnost) {
        this.klienti.addKlient(klient);
        this.ukony.addUkon(ukon, this.klienti.getKlient(klient).getId(), TypSluzby.getISluzba(typ));
        this.mesic.addDenniZaznam(den, zacatek, konec, typ, klient, ukon, doprava, prestavka, nepritomnost);
        this.monthSaved = false;
    }

    public void editDenniZaznam(int den, int pozice, Map<Integer, Object> prop) {
        this.klienti.addKlient((String) prop.get(DenniZaznam.PROP_KLI));
        this.ukony.addUkon((String)prop.get(DenniZaznam.PROP_UKO),
                this.klienti.getKlient((String) prop.get(DenniZaznam.PROP_KLI)).getId(),
                TypSluzby.getISluzba((String) prop.get(DenniZaznam.PROP_TYP)));
        this.mesic.editDenniZaznam(den, pozice, prop);
        this.monthSaved = false;
    }

    public void removeDenniZaznam(int den, int polozka) {
        this.mesic.removeDenniZaznam(den, polozka);
        this.monthSaved = false;
    }

    public void convert() {
        FileOutputStream fos = null;
        FileInputStream fin = null;
        try {
            fin = new FileInputStream(this.xslVzor);
            HSSFWorkbook wb = new HSSFWorkbook(fin);
            HSSFSheet sheet0 = wb.getSheetAt(0);
            sheet0.getRow(3).getCell(3).setCellValue(this.nastaveni.get(Model.SETTINGS_USER));
            this.mesic.export(wb);
            File vystup = new File(this.getSetting(SETTINGS_XLS) + this.mesic.toString() + ".xls");
            if (!vystup.exists()) {
                vystup.createNewFile();
            }
            fos = new FileOutputStream(vystup);
            wb.write(fos);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                fos.close();
                fin.close();
            } catch (IOException ex) {
                Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public List<String> getKlienti() {
        return this.klienti.getKlienti();
    }

    public List<String> getUkony(String klient) {
        try {
            return this.klienti.getKlient(klient).getKlientUkony();
        } catch (NullPointerException ex) {
            return new ArrayList<String>();
        }
    }

    public Set<Integer> getTyp(String ukon) {
        return this.ukony.getTypy(ukon);
    }

    public Boolean isPrestavka(int den) {
        return this.mesic.isPrestavka(den);
    }

    public Time getPosledni(int den) {
        return this.mesic.getPosledni(den);
    }

    public void saveMonth(File cesta) {
        if (this.mesic == null){
            return;
        }
        ObjectOutputStream os = null;
        if (!this.isSaveFile()) {
            if (!cesta.exists()) {
                try {
                    cesta.createNewFile();
                } catch (IOException ex) {
                    Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            try {
                os = new ObjectOutputStream(new FileOutputStream(cesta));
                os.writeUnshared(this.mesic);
                os.flush();
                this.mesicFile = cesta;
                this.monthSaved = true;
            } catch (IOException ex) {
                Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    os.close();
                } catch (IOException ex) {
                    Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        } else {
            try {
                os = new ObjectOutputStream(new FileOutputStream(this.mesicFile));
                os.writeUnshared(this.mesic);
                os.flush();
                this.monthSaved = true;
            } catch (IOException ex) {
                Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    os.close();
                } catch (IOException ex) {
                    Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    public Boolean isSaveFile() {
        if (this.mesicFile != null && this.mesicFile.exists()) {
            return true;
        }
        return false;
    }

    public Boolean isSaved() {
        if (mesic != null) {
            return this.monthSaved;
        }
        return true;
    }

    public void saveAll() {
        this.ukony.save();
        this.klienti.save();
    }

    private String getSetting(Integer nast) {
        return this.nastaveni.get(nast);
    }

    public Map<Integer, String> getSettings() {
        return Collections.unmodifiableMap(this.nastaveni);
    }
}
